package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.domain.Dto.SpendDetailDto;
import com.ruoyi.system.domain.Dto.SysSpendDto;
import com.ruoyi.system.domain.Dto.TimeDto;
import com.ruoyi.system.domain.SpendDetail;
import com.ruoyi.system.domain.SysSpend;
import com.ruoyi.system.domain.SysTotalBill;
import com.ruoyi.system.domain.vo.BillStatistic;
import com.ruoyi.system.domain.vo.SpendDetailVo;
import com.ruoyi.system.domain.vo.SysSpendVo;
import com.ruoyi.system.mapper.SpendMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.service.SpendService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.PageUtils.startPage;
import static com.ruoyi.common.utils.SecurityUtils.getUserId;

/**
 * @Author chenyouliang
 * @create 2024/11/14 10:03
 */
@Service
@Slf4j
public class SpendServiceImpl implements SpendService {
    @Autowired
    private SpendMapper spendMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;

    /**
     * 获取花销列表
     *
     * @param sysSpend
     * @return
     */
    @Override
    public List<SysSpend> selectSpendList(SysSpend sysSpend) {
        // 获取用户ID
        Long userId = getUserId();
        // 获取角色
        List<SysRole> sysRoles = sysRoleMapper.selectRolePermissionByUserId(userId);
        if (!("admin".equals(sysRoles.get(0).getRoleKey()))) {
            sysSpend.setUserId(userId);
        }
        startPage();
        List<SysSpend> sysSpendList = spendMapper.selectSpendList(sysSpend);
        sysSpendList.forEach(item -> {
            // 获取花销详情
            List<SpendDetail> spendDetailList = spendMapper.getSpendDetail(item.getId());
            spendDetailList.forEach(v -> v.setUserId(item.getUserId()));
            item.setSpendDetails(spendDetailList);
        });
        return sysSpendList;
    }

    /**
     * 新增花销
     *
     * @param spendDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertSpend(SysSpendDto spendDto) {
        // 获取存在的对象
        Long userId = getUserId();
        List<SysSpend> spendList = spendMapper.getSpendByTime(spendDto.getSpendingTime(), userId);
        if (spendList != null && spendList.size() > 0) {
            throw new RuntimeException("当前时间重复，请重新选择");
        }
        // 创建对象
        SysSpend spend = new SysSpend();
        BeanUtils.copyProperties(spendDto, spend);
        spend.setBillId("ZDBH-" + System.currentTimeMillis());
        return spendMapper.insertSpend(spend);
    }

    /**
     * 删除花销
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(Long[] ids) {
        // 删除花销列表
        spendMapper.deleteByIds(ids);
        // 存在详情的账单数据id
        List<Long> detailIds = new ArrayList<>();
        // 获取存在详情的账单数据
        for (Long id : ids) {
            List<SpendDetail> detailList = spendMapper.getSpendDetail(Math.toIntExact(id));
            if (detailList != null && detailList.size() > 0) {
                detailIds.add(id);
            }
        }
        log.info("ids为：{}", detailIds);
        if (detailIds.size() > 0) {
            // 删除花销列表详情
            spendMapper.deleteDetailByIds(detailIds);
        }
        return 1;
    }

    /**
     * 删除单个花销详情
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteDetailById(Integer id) {
        // 添加实际金额
        SpendDetail spendDetail = spendMapper.getDetailById(id);
        log.info("spendDetail:{}", spendDetail);
        updateActualAmount(spendDetail.getSpendId(), spendDetail.getPrice());
        return spendMapper.deleteDetailById(id);
    }

    /**
     * 修改单个花销详情
     *
     * @param spendDetail
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int editDetail(SpendDetail spendDetail) {
        spendMapper.editDetail(spendDetail);
        // 添加实际金额
        updateActualAmount(spendDetail.getSpendId(), 0.0);
        return 1;
    }

    /**
     * 根据id获取详细信息
     */
    @Override
    public SysSpendVo getInfo(Integer id) {
        // 创建对象
        SysSpendVo spendVo = new SysSpendVo();
        // 获取花销
        SysSpend sysSpend = spendMapper.getSpend(id);
        // 获取花销详情
        List<SpendDetail> spendDetailList = spendMapper.getSpendDetail(id);
        BeanUtils.copyProperties(sysSpend, spendVo);
        spendDetailList.forEach(item -> item.setSpendId(sysSpend.getId()));
        spendVo.setSpendDetails(spendDetailList);
        return spendVo;
    }

    /**
     * 修改花销详情
     *
     * @param spendDto
     */
    @Override
    public void updateSpend(SysSpendDto spendDto) {
        // 创建对象
        SysSpend spend = new SysSpend();
        BeanUtils.copyProperties(spendDto, spend);
        // 修改花销记录
        spendMapper.updateSpend(spend);
    }

    /**
     * 获取账单详情列表
     *
     * @param spendDetailDto
     * @return
     */
    @Override
    public List<SpendDetail> selectDetailList(SpendDetailDto spendDetailDto) {
        // 获取用户ID
        Long userId = getUserId();
        if (userId == 1) {
            spendDetailDto.setUserId(null);
        } else {
            spendDetailDto.setUserId(userId);
        }
        return spendMapper.selectDetailList(spendDetailDto);
    }

    /**
     * 新增账单详情列表
     *
     * @param spendDetail
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addDetailList(SpendDetail spendDetail) {
        // 添加账单明细
        spendDetail.setUserId(getUserId());
        spendMapper.addDetailList(spendDetail);
        // 添加实际金额
        updateActualAmount(spendDetail.getSpendId(), 0.0);
        return 1;
    }

    @Override
    public List<SysSpend> listTree(SysSpend sysSpend) {
        // 获取用户ID
        Long userId = getUserId();
        // 获取角色
        List<SysRole> sysRoles = sysRoleMapper.selectRolePermissionByUserId(userId);
        if (!("admin".equals(sysRoles.get(0).getRoleKey()))) {
            sysSpend.setUserId(userId);
        }
        return spendMapper.selectSpendList(sysSpend);
    }

    /**
     * 获取总账单列表
     *
     * @param sysTotalBill
     * @return
     */
    @Override
    public List<SysTotalBill> totalBillList(SysTotalBill sysTotalBill) {
        // 获取用户ID
        Long userId = getUserId();
        if (userId == 1) {
            return spendMapper.totalBillList(sysTotalBill);
        } else {
            sysTotalBill.setUserId(userId);
            return spendMapper.totalBillList(sysTotalBill);
        }
    }

    /**
     * 获取总账单列表详情
     *
     * @param sysTotalBill
     * @return
     */
    @Override
    public SysTotalBill totalBillDetail(SysTotalBill sysTotalBill) {
        return spendMapper.totalBillDetail(sysTotalBill);
    }

    /**
     * 新增总账单
     *
     * @param sysTotalBill
     * @return
     */
    @Override
    public int totalBillAdd(SysTotalBill sysTotalBill) {
        // 获取用户ID
        Long userId = getUserId();
        List<SysTotalBill> spendBillList = spendMapper.getDepositByTime(sysTotalBill.getDepositTime(), userId);
        if (spendBillList != null && spendBillList.size() > 0) {
            throw new RuntimeException("当前时间重复，请重新选择");
        }
        // 获取每月存款
        Double deposit = sysTotalBill.getWages() - sysTotalBill.getSpendTotalPrice();
        sysTotalBill.setDeposit(deposit);
        sysTotalBill.setUserId(userId);
        spendMapper.totalBillAdd(sysTotalBill);
        return 1;
    }

    @Override
    public int totalBillUpdate(SysTotalBill sysTotalBill) {
        // 获取每月存款
        Double deposit = sysTotalBill.getWages() - sysTotalBill.getSpendTotalPrice();
        sysTotalBill.setDeposit(deposit);
        spendMapper.totalBillUpdate(sysTotalBill);
        return 1;
    }

    /**
     * 获取总账单统计
     *
     * @param yearTime
     * @return
     */
    @Override
    public BillStatistic getStatistic(String yearTime) {
        // 获取用户ID
        Long userId = getUserId();
        BillStatistic billStatistic = new BillStatistic();
        String year;
        if (StringUtils.isEmpty(yearTime) || "null".equals(yearTime)) {
            Calendar calendar = Calendar.getInstance();
            // 获取当前年份
            year = String.valueOf(calendar.get(Calendar.YEAR));
        } else {
            year = yearTime;
        }
        // 获取当前年的第一个月和最后一个月
        String startTime = year + "-01";
        String endTime = year + "-12";
        // 获取当前年的第一个月和最后一个月日期
        String startTimeDay = year + "-01-01";
        String endTimeDay = year + "-12-31";
        Double totalPrice = spendMapper.getTotalPrice(startTime, endTime, userId);
        Double totalWages = spendMapper.getTotalWages(startTime, endTime, userId);
        Double totalDeposit = spendMapper.getTotalDeposit(startTime, endTime, userId);
        Double topPrice = spendMapper.getTopPrice(startTimeDay, endTimeDay, userId);
        billStatistic.setTotalPrice(totalPrice);
        billStatistic.setTotalWages(totalWages);
        billStatistic.setTotalDeposit(totalDeposit);
        billStatistic.setTopPrice(topPrice);
        return billStatistic;
    }

    /**
     * 获取每个月账单统计
     *
     * @param monthTime
     * @return
     */
    @Override
    public List<SysSpend> getMonthStatistic(String monthTime) {
        SysSpend sysSpend = new SysSpend();
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate localDate = LocalDate.now();
        // 获取用户ID
        Long userId = getUserId();
        sysSpend.setUserId(userId);
        Map<String, Object> params = new HashMap<>();
        // 回去当前月份的第一天和最后一天
        String month;
        if (StringUtils.isEmpty(monthTime) || "null".equals(monthTime)) {
            month = localDate.format(fmt);
        } else {
            month = monthTime;
        }
        LocalDate date = LocalDate.parse(month, fmt);
        // 获取当前月的第一天
        LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
        // 获取当前月的最后一天
        LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
        params.put("beginTime", firstDay);
        if (StringUtils.isEmpty(monthTime) || "null".equals(monthTime)) {
            params.put("endTime", date);
        } else {
            params.put("endTime", lastDay);
        }
        sysSpend.setParams(params);
        return spendMapper.selectSpendList(sysSpend);
    }

    /**
     * 获取每年账单前五统计
     *
     * @param yearTime
     * @return
     */
    @Override
    public List<SysTotalBill> getTop(String yearTime) {
        // 获取用户ID
        Long userId = getUserId();
        String year;
        if (StringUtils.isEmpty(yearTime) || "null".equals(yearTime)) {
            Calendar calendar = Calendar.getInstance();
            // 获取当前年份
            year = String.valueOf(calendar.get(Calendar.YEAR));
        } else {
            year = yearTime;
        }
        // 获取当前年的第一个月和最后一个月
        String startTime = year + "-01";
        String endTime = year + "-12";
        return spendMapper.getTop(startTime, endTime, userId);
    }

    @Override
    public String getTotalActual(TimeDto timeDto) {
        // 获取用户ID
        Long userId = getUserId();
        return spendMapper.getTotalActual(timeDto.getBeginTime(), timeDto.getEndTime(), userId);
    }

    @Override
    public List<SysSpendVo> getSpendDetail(SpendDetailDto spendDetail) {
        SysSpend sysSpend = new SysSpend();
        // 获取用户ID
        Long userId = getUserId();
        // 获取角色
        List<SysRole> sysRoles = sysRoleMapper.selectRolePermissionByUserId(userId);
        if (!("admin".equals(sysRoles.get(0).getRoleKey()))) {
            sysSpend.setUserId(userId);
        }
        List<SpendDetailVo> sysSpendList = spendMapper.getSpendDetailData(spendDetail.getName(),userId);
        // 使用 Stream API 聚合数据
        List<SysSpendVo> result = sysSpendList.stream()
                .collect(Collectors.groupingBy(SpendDetailVo::getSpendId))
                .entrySet().stream()
                .map(entry -> {
                    Integer id = entry.getKey();
                    List<SpendDetailVo> group = entry.getValue();
                    SpendDetailVo first = group.get(0);
                    // 构建车票项目列表
                    List<SpendDetail> ticketItems = group.stream()
                            .map(record -> new SpendDetail(record.getIdDetail(), record.getName(), record.getPrice(), record.getSpendId(), record.getUserId()))
                            .collect(Collectors.toList());
                    SysSpendVo sysSpendVo = new SysSpendVo();
                    sysSpendVo.setId(id);
                    sysSpendVo.setBillId(first.getBillId());
                    sysSpendVo.setActualAmount(first.getActualAmount());
                    sysSpendVo.setSpendingTime(first.getSpendingTime());
                    sysSpendVo.setSpendingPrice(first.getSpendingPrice());
                    sysSpendVo.setUserId(first.getUserId());
                    sysSpendVo.setSpendDetails(ticketItems);
                    sysSpendVo.setRemark(first.getRemark());
                    sysSpendVo.setCreateTime(first.getCreateTime());
                    sysSpendVo.setUpdateTime(first.getUpdateTime());
                    sysSpendVo.setCreateBy(first.getCreateBy());
                    sysSpendVo.setUpdateBy(first.getUpdateBy());
                    sysSpendVo.setRemark(first.getRemark());
                    return sysSpendVo;
                })
                .collect(Collectors.toList());
       return result;
    }

    /**
     * 修改实际账单
     */
    public void updateActualAmount(Integer id, Double price) {
        // 获取账单数据
        SysSpendVo spendVo = getInfo(id);
        Double actualAmount = 0.00;
        // 计算实际金额
        for (SpendDetail detail : spendVo.getSpendDetails()) {
            actualAmount += detail.getPrice();
        }
        spendVo.setActualAmount(actualAmount - price);
        SysSpend sysSpend = new SysSpend();
        BeanUtils.copyProperties(spendVo, sysSpend);
        spendMapper.updateSpend(sysSpend);
    }
}
